﻿using Simple.Tools;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

/*********************************************************
 * 命名空间 Simple.BasicNet.Core.Container
 * 接口名称 TypeMapping
 * 开发人员：11920
 * 创建时间：2023/4/6 13:02:08
 * 描述说明：
 * 更改历史：
 * 
 * *******************************************************/
namespace Simple.Framework.Ioc
{
    internal class TypeMapper : ITypeMapper
    {
        public TypeMapper(Type original, Type target, eLifeCycle lifeCycle,object o=null)
        {
            Original = original;
            Target = new Dictionary<string, Tuple<Type, object>>();
            
			LifeCycle = lifeCycle;
            IsAutowired = false;
            AutowiredType = typeof(AutowiredAttribute);//默认
            if (ToolSimpleCheck.IsNullOrEmpty( this.token))
            {
				this.token = target.FullName;
				AddTarget(target, token, o);
			}
		}

        public TypeMapper(Type original, Type target, eLifeCycle lifeCycle, string token, object o = null) :this( original,  target,  lifeCycle, o)
		{
            if (!ToolSimpleCheck.IsNullOrEmpty(token))
            {
				this.token = token;
				AddTarget(target, token, o);
			}
		}
        /// <summary>
        /// 
        /// </summary>
        /// <param name="original"></param>
        /// <param name="target"></param>
		public TypeMapper(Type original, Type target) : this(original, target, eLifeCycle.Instant)
        {
		}
        /// <summary>
        /// 指定名称
        /// </summary>
        /// <param name="original"></param>
        /// <param name="target"></param>
        /// <param name="token"></param>
		public TypeMapper(Type original, Type target,string token) : this(original, target, eLifeCycle.Instant,token)
		{
		}

		public TypeMapper(Type target, eLifeCycle lifeCycle) : this(target, target, lifeCycle)
        {
		}
        public TypeMapper(Type target) : this(target, eLifeCycle.Instant)
        {
		}

        public TypeMapper(Type originalType, Type targetType,object target): this(originalType, targetType, eLifeCycle.Single,target)
		{

		}

		public TypeMapper(Type originalType, Type targetType, string token,object target) : this(originalType, targetType, eLifeCycle.Single,token, target)
		{

		}

		public Type Original { get { return original; } set { original = value; } }
        /// <summary>
        /// key 目标类型名称
        /// tuple type 目标类型type
        /// tuple object 目标类型
        /// </summary>
        public Dictionary<string, Tuple<Type, object>> Target { get { return target; } set { target = value; } }
        /// <summary>
        /// 生命周期
        /// </summary>
        public eLifeCycle LifeCycle { get { return lifeCycle; } set { lifeCycle = value; } }
        /// <summary>
        /// 最后注册的key
        /// </summary>
        public string TargetKey { get { return targetKey; } set { targetKey = value; } }
        /// <summary>
        /// 属性类型自动注册
        /// </summary>
        public bool IsAutowired { get { return isAutowired; } set { isAutowired = value; } }

        /// <summary>
        /// 自定义自动注册标记的类型
        /// </summary>
        public Type AutowiredType { get { return autowiredType; } set { autowiredType = value; } }

        private Type original;
        private Dictionary<string, Tuple<Type, object>> target;
        private eLifeCycle lifeCycle;
        private string targetKey;
        private string token;
        private bool isAutowired;
        private Type autowiredType;
        /// <summary>
        /// 添加一个类型记录
        /// </summary>
        /// <param name="target"></param>
        public void AddTarget(Type target)
        {
            AddTarget(target, null);
        }
        /// <summary>
        /// 适用于注册全局单例
        /// </summary>
        /// <param name="target"></param>
        /// <param name="o"></param>
        public void AddTarget(Type target,object o)
        {
            AddTarget(target,target.FullName,o);
		}

		public void AddTarget(Type target,string token, object o)
		{
			if (!Target.ContainsKey(token))
			{
				TargetKey = token;
				Target.Add(TargetKey, Tuple.Create(target, o));
			}
		}
		/// <summary>
		/// 原始类型key
		/// </summary>
		/// <returns></returns>
		//public string GetTypeMapperKey()
  //      {
  //          return token;
  //      }
        public string OriginalKey()
        {
            return Original.FullName;

		}
		/// <summary>
		/// 验证是否是继承关系
		/// 目标类必须继承接口或者是子类
		/// </summary>
		/// <exception cref="Exception"></exception>
		public void Verify()
        {
            if (!GetTargetType(TargetKey).IsAssignableTo(Original)
                && !GetTargetType(TargetKey).GetInterfaces().Any(t => t.FullName == Original.FullName))
                throw new Exception("注册失败,TTarget类型必须继承或者实现Original类型!");
        }
        /// <summary>
        /// target key 获取对象
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public Type GetTargetType(string key)
        {
            if (Target.ContainsKey(key))
            {
                return Target[key].Item1;
            }
            if (key==original.FullName)
            {
                // tar
               return  target.FirstOrDefault().Value.Item1;
			}
            return default;
        }
        /// <summary>
        ///获取object 通过key 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public object GetInstance(string key)
        {
            if (Target.ContainsKey(key))
            {
                return Target[key].Item2;
            }
            return default;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="target"></param>
        public void SetInstance(string key, object target)
        {
            if (Target.ContainsKey(key))
            {
                Target[key] = Tuple.Create(target.GetType(), target);
            }
        }
        #region 
        public void Autowired()
        {
            isAutowired = true;
        }
        public void Autowired(Type type)
        {
            autowiredType = type;
            Autowired();
        }
        #endregion
    }
}
